"""
简历解析器 - Resume Parser

该模块提供了一个简历解析器，可以从PDF和DOCX格式的简历文件中提取文本内容，
并使用硅基流动平台的AI服务将简历内容结构化为JSON格式。
"""

import os
import json
import docx
import PyPDF2
from openai import OpenAI
from typing import Dict, Any, Union
from pathlib import Path
from dotenv import load_dotenv
import glob

# pip install python-docx PyPDF2 openai dotenv

def get_api_key():
    """获取API密钥
    从环境变量中获取硅基流动平台API密钥
    Returns:
        API密钥
    """
    if os.path.exists(".env"):
        load_dotenv(".env")
        api_key = os.environ.get("SILICONFLOW_API_KEY", "")
        return api_key
    else:
        print("未找到.env文件，请确保环境变量已正确配置")
        return None


def get_base_url(platform="siliconflow"):
    """获取API基础URL
    Args:
        platform: 平台名称，默认为siliconflow
    Returns:
        API基础URL
    """
    if platform == "siliconflow":
        return "https://api.siliconflow.cn/v1"
    else:
        print("不支持的平台")
        return None


def ai_chat(prompt: str, **kwargs):
    """调用AI接口进行对话
    Args:
        prompt: 提示词
        **kwargs: 其他参数，包括model、temperature、max_tokens、stream等
    Returns:
        AI响应结果
    """
    api_key = get_api_key()
    if not api_key:
        print("未提供API密钥，请通过参数传入或设置SILICONFLOW_API_KEY环境变量")
        return None
    
    # 获取API基础URL
    base_url = get_base_url()

    client = OpenAI(api_key=api_key, base_url=base_url)

    stream = kwargs.get("stream", True)
    response = client.chat.completions.create(
        model=kwargs.get("model", "deepseek-ai/DeepSeek-V3"),
        messages=[
            {"role": "system", "content": "You are a helpful assistant"},
            {"role": "user", "content": f"{prompt}"},
        ],
        temperature=kwargs.get("temperature", 0.2),
        max_tokens=kwargs.get("max_tokens", 4096),
        stream=stream,
    )

    if stream:
        contents = ""
        print("\nAI回复：")
        for chunk in response:
            content = chunk.choices[0].delta.content
            print(content, end="", flush=True)
            contents += content
    else:
        contents = response.choices[0].message.content
        print("\nAI回复：")
        print(contents)

    return contents


def extract_text_from_pdf(file_path: Union[str, Path]) -> str:
    """从PDF文件中提取文本
    Args:
        file_path: PDF文件路径
    Returns:
        提取的文本内容
    Raises:
        Exception: 文件读取或解析失败时抛出异常
    """
    try:
        with open(file_path, 'rb') as file:
            reader = PyPDF2.PdfReader(file)
            text = ""
            for page in reader.pages:
                text += page.extract_text() + "\n"
            return text
    except Exception as e:
        raise Exception(f"PDF文件解析失败: {str(e)}")


def extract_text_from_docx(file_path: Union[str, Path]) -> str:
    """从DOCX文件中提取文本
    Args:
        file_path: DOCX文件路径
    Returns:
        提取的文本内容
    Raises:
        Exception: 文件读取或解析失败时抛出异常
    """
    try:
        doc = docx.Document(file_path)
        text = "\n".join([paragraph.text for paragraph in doc.paragraphs if paragraph.text.strip()])
        return text
    except Exception as e:
        raise Exception(f"DOCX文件解析失败: {str(e)}")


def extract_text(file_path: Union[str, Path]) -> str:
    """从文件中提取文本
    Args:
        file_path: 文件路径
    Returns:
        提取的文本内容
    Raises:
        ValueError: 不支持的文件格式
        Exception: 文件读取或解析失败时抛出异常
    """
    # 将文件路径转换为Path对象，Path是pathlib库提供的类，它提供了一个面向对象的文件系统路径接口
    # 相比字符串路径，Path对象提供了更多实用的方法，如:
    # - 路径拼接 (/)
    # - 获取文件扩展名 (suffix)
    # - 获取父目录 (parent)
    # - 判断文件是否存在 (exists())
    # - 创建目录 (mkdir())
    # 等功能
    file_path = Path(file_path)
    file_extension = file_path.suffix.lower()
    
    print(f"正在解析文件: {file_path}")
    if file_extension == ".pdf":
        return extract_text_from_pdf(file_path)
    elif file_extension == ".docx":
        return extract_text_from_docx(file_path)
    else:
        raise ValueError(f"不支持的文件格式: {file_extension}，目前仅支持PDF和DOCX格式")


def structure_resume(text: str) -> Dict[str, Any]:
    """使用AI服务将简历文本结构化
    Args:
        text: 简历文本内容
    Returns:
        结构化的简历数据
    Raises:
        Exception: AI服务调用失败时抛出异常
    """
    prompt = f"""
    请将以下简历文本解析为结构化的JSON格式，包含以下字段：
    - basic_info: 基本信息：姓名、年龄、电话、邮箱等
    - education: 教育经历：学校、专业、学历、起止时间等
    - work_experience: 工作经历：公司名称、职位、起止时间、工作描述等
    - project_experience: 项目经历：项目名称、角色、起止时间、项目描述等
    - skill: 技能：技术技能、语言能力、证书等

    简历文本：
    {text}

    请只返回JSON格式的结果，不要包含其他解释性文字。
    """
    
    try:
        print("正在调用AI服务...")
        # 调用AI服务
        response = ai_chat(prompt=prompt)
        response = response.replace("```json", "").replace("```", "")

        # 尝试解析JSON
        try:
            return json.loads(response)
        except json.JSONDecodeError:
            # JSON解析失败，抛出异常
            raise Exception(f"AI返回的结果无法解析为JSON: {response}")
            
    except Exception as e:
        raise Exception(f"AI结构化简历失败: {str(e)}")


def parse_resume(file_path: Union[str, Path]) -> Union[Dict, str]:
    """解析简历文件
    Args:
        file_path: 简历文件路径
    Returns:
        结构化的简历数据
    Raises:
        FileNotFoundError: 文件不存在
        ValueError: 不支持的文件格式
        Exception: 文件读取、解析或AI服务调用失败时抛出异常
    """
    file_path = Path(file_path)
    
    # 检查文件是否存在
    if not file_path.exists():
        raise FileNotFoundError(f"文件不存在: {file_path}")
    
    # 提取文本
    text = extract_text(file_path)
    
    # 使用AI服务结构化简历
    result = structure_resume(text)
    
    return result


def main():
    """主函数，自动处理test_resumes文件夹中的所有简历文件"""
    # 简历文件夹路径
    resume_dir = "test_resumes"
    
    print("=== 简历解析器 ===")
    print(f"正在处理文件夹: {resume_dir}")
    
    # 获取所有PDF和DOCX文件，并排除临时文件
    resume_files = []
    for ext in ['*.pdf', '*.docx']:
        files = glob.glob(os.path.join(resume_dir, ext))
        # 过滤掉以~$开头的临时文件
        resume_files.extend([f for f in files if not os.path.basename(f).startswith('~$')])
    
    if not resume_files:
        print("未找到任何简历文件，请确保test_resumes文件夹中包含PDF或DOCX格式的简历文件")
        return False
    
    print(f"找到 {len(resume_files)} 个简历文件:")
    for file in resume_files:
        print(f"  - {file}")
    
    # 处理每个简历文件
    for file_path in resume_files:
        print(f"\n正在处理: {file_path}")
        try:
            # 解析简历
            result = parse_resume(file_path)
            print(f"\n简历解析结果: {result}")
                
        except Exception as e:
            print(f"处理文件 {file_path} 时出错: {str(e)}")
    
    print("\n=== 所有简历处理完成 ===")
    return True


if __name__ == "__main__":
    main()